namespace Microsoft.ServiceModel.Samples.Discovery.Protocol
{
    using System;
    using System.Xml;
    using System.Globalization;
    using System.Xml.Serialization;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    
    internal class SerializationUtility
    {
        SerializationUtility()
        {
        }

        public static void WriteListOfQNames(XmlWriter writer, Collection<XmlQualifiedName> qnames)
        {
            if (qnames.Count == 0) return;

            List<string> prefixedQNames = new List<string>();
            string qNamePrefix;
            string encodedLocalName;
            bool emptyNsDeclared = false;
            int prefixCount = 0;
            foreach (XmlQualifiedName qname in qnames)
            {
                if (qname.Name.Trim().Length == 0)
                    throw new XmlException(ErrorMessages.EmptyTypeName);

                encodedLocalName = XmlConvert.EncodeLocalName(qname.Name);

                if (qname.Namespace.Length == 0)
                {
                    if (!emptyNsDeclared)
                    {
                        writer.WriteAttributeString("xmlns", string.Empty, null, string.Empty);
                        emptyNsDeclared = true;
                    }

                    qNamePrefix = null;
                }
                else
                {
                    // lookup the prefix.
                    qNamePrefix = writer.LookupPrefix(qname.Namespace);

                    if (qNamePrefix == null)
                    {
                        qNamePrefix = "dp" + prefixCount++;
                        writer.WriteAttributeString("xmlns", qNamePrefix, null, qname.Namespace);
                    }
                }

                if (!string.IsNullOrEmpty(qNamePrefix))
                    prefixedQNames.Add(string.Format(CultureInfo.InvariantCulture, 
                        "{0}:{1}", qNamePrefix, encodedLocalName));
                else
                    prefixedQNames.Add(encodedLocalName);
            }

            // 3. write the prefixed qnames
            for(int i = 0; i < prefixedQNames.Count-1; i++)
            {
                writer.WriteString(prefixedQNames[i]);
                writer.WriteWhitespace(" ");
            }

            writer.WriteString(prefixedQNames[prefixedQNames.Count - 1]);
        }

        public static List<XmlQualifiedName> ReadContentAsListOfQNames(XmlReader reader)
        {
            string emptyPrefixNS = reader.NamespaceURI;
            List<XmlQualifiedName> qnames = new List<XmlQualifiedName>();

            string listOfQNamesAsStr = reader.ReadString();
            if (string.IsNullOrEmpty(listOfQNamesAsStr)) return qnames;

            string[] prefixedQNames = listOfQNamesAsStr.Split(null);
            for(int i = 0; i < prefixedQNames.Length; i++)
            {
                if (prefixedQNames[i].Length > 0)
                    qnames.Add(ParseQName(prefixedQNames[i], reader, emptyPrefixNS));
            }

            return qnames;
        }

        public static XmlQualifiedName ParseQName(string prefixedQName, XmlReader reader,
            string emptyPrefixNS)
        {
            int index = prefixedQName.IndexOf(':');

            string prefix = null;
            string localname = null;

            if (index != -1)
            {
                prefix = prefixedQName.Substring(0, index);
                localname = prefixedQName.Substring(index + 1);
            }
            else
            {
                prefix = string.Empty;
                localname = prefixedQName;
            }

            string ns = emptyPrefixNS;
            if (prefix.Length > 0)
            {
                ns = reader.LookupNamespace(prefix);
                if (ns == null)
                    throw new XmlException(string.Format(CultureInfo.InvariantCulture,
                        ErrorMessages.PrefixNotDefined, prefix, prefixedQName));
            }
            
            localname = XmlConvert.DecodeName(localname);
            return new XmlQualifiedName(localname, ns);
        }


        public static void WriteListOfUris(XmlWriter writer, Collection<Uri> uris)
        {
            // 2. write the Uris seperated by whitespace
            if (uris.Count > 0)
            {
                for (int i = 0; i < uris.Count - 1; i++)
                {
                    writer.WriteString(uris[i].GetComponents(
                        UriComponents.SerializationInfoString,
                        UriFormat.UriEscaped));

                    writer.WriteWhitespace(" ");
                }

                writer.WriteString(uris[uris.Count - 1].GetComponents(
                     UriComponents.SerializationInfoString,
                     UriFormat.UriEscaped));
            }
        }

        public static List<Uri> ReadContentAsListOfUris(XmlReader reader)
        {
            List<Uri> uris = new List<Uri>();
            string listOfUrisAsString = reader.ReadString();
            if (string.IsNullOrEmpty(listOfUrisAsString)) return uris;

            string[] uristrs = listOfUrisAsString.Split(null);
            for (int i = 0; i < uristrs.Length; i++)
            {
                if (uristrs[i].Length > 0)
                {
                    uris.Add(new Uri(uristrs[i], UriKind.RelativeOrAbsolute));
                }
            }

            return uris;
        }
    }
}
